/*
 * dbm_pm.c
 *
 *  Created on: 2012-12-5
 *      Author: macro
 */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "cmn/utils.h"
#include "pdb/pma_err.h"
#include "pdb/pm_inner.h"

static struct policy_list * policy_list;

//init the policy list
int policy_list_init()
{
	policy_list = (struct policy_list *)malloc(sizeof(struct policy_list));
	assert(policy_list);

	policy_list->policy_count = 0;
	policy_list->version = 0;
	policy_list->plist_head = (struct plist_element *)malloc(sizeof(struct plist_element));
	policy_list->plist_head->lower_limit = 0;
	policy_list->plist_head->up_limit = 0;
	policy_list->plist_head->policy = NULL;
	policy_list->plist_head->prev = policy_list->plist_head;
	policy_list->plist_head->next = NULL;

	return SUCCESS;
}

//insert a element into the initialed policy list
int plist_element_insert(u64 up_limit, u64 lower_limit, struct plist_element * p_element)
{
//	p_element = NULL;

	if(policy_list == NULL)
	{
		perror("[PMA_PM]Policy List is not initialed!");
		return ENORMERR;
	}

//	p_element = (struct plist_element *)malloc(sizeof(struct plist_element));
	assert(p_element);

	p_element->up_limit = up_limit;
	p_element->lower_limit = lower_limit;
	p_element->prev = NULL;
	p_element->next = NULL;
	p_element->policy = NULL;

	struct plist_element * ptr_element = policy_list->plist_head->next;

	if(ptr_element == NULL)
	{
		policy_list->plist_head->next = p_element;
		p_element->prev = policy_list->plist_head;

		policy_list->policy_count++;
		return SUCCESS;
	}

	//make the range have a descending order
	while(ptr_element != NULL)
	{
		if(p_element->lower_limit >= ptr_element->up_limit)
		{

			ptr_element->prev->next = p_element;
			p_element->next = ptr_element;
			ptr_element->prev = p_element;

			policy_list->policy_count++;
			return SUCCESS;
		}
		else if(ptr_element->lower_limit >= p_element->up_limit)
		{
			if(ptr_element->next == NULL)
			{
				ptr_element->next = p_element;
				p_element->prev = ptr_element;

				policy_list->policy_count++;
				return SUCCESS;
			}
			ptr_element = ptr_element->next;
			continue;
		}
		else
		{
			perror("[PMA_PM]Policy's range is illegal!");

			return ENORMERR;
		}
	}

	return ENORMERR;
}

//add parameter to the policy
int policy_para_add(struct policy * policy, u64 para_value)
{
	assert(policy);
	struct op_para * ptr_para = policy->para_list;

	while(ptr_para->next_para != NULL)
	{
		ptr_para = ptr_para->next_para;
	}

	struct op_para * para = (struct op_para *)malloc(sizeof(struct op_para));
	assert(para);
	para->next_para = NULL;
	ptr_para->next_para = para;
	para->para_value = para_value;

	return SUCCESS;
}

//delete the policy
int delete_policy(struct plist_element * element)
{
	struct op_para * ptr_para = element->policy->para_list;
	if(element->policy->para_list)
	{
		free(element->policy->para_list);
		element->policy->para_list = NULL;
	}


//	Tag: while(ptr_para->next_para != NULL)
//	{
//		DEBUG(INFO, "%p ---> %p ",ptr_para, ptr_para->next_para);
//		ptr_para = ptr_para->next_para;
//	}
//
//	if(ptr_para->next_para == NULL)
//	{
//		ptr_para->para_value = 0;
//		if(ptr_para)
//		{
//			free(ptr_para);
//			ptr_para = NULL;
//		}
//	}
//
//	ptr_para = element->policy->para_list;
//
//	if(ptr_para->next_para != NULL)
//	{
//		goto Tag;
//	}
//	else
//	{
//		if(ptr_para)
//		{
//			free(element->policy->para_list);
//			element->policy->para_list = NULL;
//		}
//	}

	if(element->policy)
	{
		free(element->policy);
		element->policy = NULL;
	}

	printf("[PMA_PM]Deleted a policy!\n");
	return SUCCESS;
}
//delete the policy list's content
int empty_policy_list()
{
	assert(policy_list);
	struct plist_element * ptr1_element = policy_list->plist_head;
	struct plist_element * ptr2_element;

	while(ptr1_element->next != NULL)
	{
		ptr1_element = ptr1_element->next;
	}

	while(ptr1_element != policy_list->plist_head)
	{

		DEBUG(INFO, "%p ---> %p ",ptr1_element, policy_list->plist_head);

		if(delete_policy(ptr1_element) == SUCCESS)
		{

			ptr2_element = ptr1_element->prev;
			ptr2_element->next = NULL;
			ptr1_element->up_limit = 0;
			ptr1_element->lower_limit = 0;
			ptr1_element->prev = NULL;

			free(ptr1_element);
			ptr1_element = NULL;

			policy_list->policy_count--;
		}

		ptr1_element = ptr2_element;
		ptr2_element = ptr1_element->prev;
	}

	if(policy_list->policy_count == 0)
	{
		policy_list->version = 0;

		return SUCCESS;
	}

	else
	{
		perror("[PMA_PM]An error exits while emptifing the policy list!");
	}

	return ENORMERR;
}

//build a policy
struct policy * policy_build(u8 operation)
{
	struct policy * policy;
	policy = (struct policy *)malloc(sizeof(struct policy));
	assert(policy);

	policy->operation_code = operation;
	policy->para_list = (struct op_para *)malloc(sizeof(struct op_para));
	policy->para_list->para_value = 0;
	policy->para_list->next_para = NULL;

	return policy;
}
//insert the policy into the policy list
int pm_policy_insert(u32 version, u64 up_limit, u64 lower_limit, struct policy * policy)
{
	assert(policy_list);
	struct plist_element * policy_element = (struct plist_element *)malloc(sizeof(struct plist_element));

	if(policy_list->version < version)
	{
		if(empty_policy_list() == SUCCESS)
		{
			plist_element_insert(up_limit, lower_limit, policy_element);
			policy_list->version = version;
		}
	}
	else if(policy_list->version == version)
	{
		plist_element_insert(up_limit, lower_limit, policy_element);
	}
	else
	{
		perror("[PMA_PM]Insert a wrong versioned policy!");

		return ENORMERR;
	}

	policy_element->policy = policy;

	return SUCCESS;

}

//get a policy decision
struct policy * pm_policy_decision(int req_value)
{
	assert(policy_list);
	struct plist_element * ptr_element = policy_list->plist_head->next;

	while(ptr_element != NULL)
	{
		if((req_value >= ptr_element->lower_limit) && (req_value < ptr_element->up_limit))
		{
			return ptr_element->policy;
		}
		else
		{
			ptr_element = ptr_element->next;

		}
	}

	if(!ptr_element)
	{
		printf("[PMA_PM]PM Can't find a policy decision!\n");
	}

	return NULL;
}

